﻿///////////////////////////////////////////////////////////////////////////////
// File:        Connection.hpp
// Author:      671643387@qq.com
// Description:
///////////////////////////////////////////////////////////////////////////////

#ifndef NIO_NET_CONNECTION_HPP_
#define NIO_NET_CONNECTION_HPP_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

#include <cassert>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <nio/net/EventHandler.hpp>
#include <nio/net/Socket.hpp>
#include <nio/net/ConnectionInputStream.hpp>
#include <nio/net/ConnectionOutputStream.hpp>

namespace nio
{
    namespace net
    {
        ///////////////////////////////////////////////////////////////////////
        class ServerThread;
        class Server;
        ///////////////////////////////////////////////////////////////////////

        class Connection : public EventHandler
        {
        public:
            typedef boost::function<void(Connection&, ConnectionInputStream&)>  ConnectionReadableFN;
            typedef boost::function<void(Connection&, ConnectionOutputStream&)> ConnectionWritableFN;
            typedef boost::function<void(Connection&)>                          PassConnectionFN;

            enum State
            {
                NORMAL,
                EXITING,
                EXIT
            };

        public:
            Connection(sock_t sock, unsigned int isSize = 0x1000, unsigned int osSize = 0x1000);
            Connection(sock_t sock, ByteBuffer isBuff,
                unsigned int isSize, ByteBuffer osBuff, unsigned int osSize);
            virtual ~Connection(void);

        public:
            int getId(void) const { return id_; }
            State getState(void) const { return state_; }
            Socket& getSocket(void) { return sock_; }
            bool setSendBufferSize(unsigned int size);
            bool setRecvBufferSize(unsigned int size);
            void shutdown(void);
            ConnectionInputStream& getInputStream(void) { return is_; }
            ConnectionOutputStream& getOutputStream(void) { return os_; }
            void setReadableFN(ConnectionReadableFN fn) { readableFN_ = fn; }
            void setWritableFN(ConnectionWritableFN fn) { writableFN_ = fn; }
            void setErrorFN(PassConnectionFN fn) { errorFN_ = fn; }
            void setHeartbeatFN(PassConnectionFN fn) { heartbeatFN_ = fn; }
            void setCloseFN(PassConnectionFN fn) { closeFN_ = fn; }
            void setUserPointer(void* pointer) { userPointer_ = pointer; }
            void* getUserPointer(void) const { return userPointer_; }

        public:
            virtual void handleInput(void);
            virtual void handleOutput(void);
            virtual void handleError(void);
            virtual void handleHeartbeat(void);

        private:
            friend class ServerThread;
            friend class Server;

            void setId(int id) { id_ = id; }
            void setState(State state) { state_ = state; }
            void setUserIO(bool on) { userIO_ = on; }
            void close(void)
            {
                assert(closeFN_);
                sock_.close();
                closeFN_(*this);
                setState(EXIT);
            }

            void setShutdownFN(boost::function<void(Connection*)> fn) { shutdownFN_ = fn; }
            void setSendBytsFN(boost::function<void(unsigned int)> fn) { os_.setSendBytsFN(fn); }
            void setRecvBytsFN(boost::function<void(unsigned int)> fn) { is_.setRecvBytsFN(fn); }

        private:
            int                                 id_;
            State                               state_;
            bool                                userIO_;

            Socket                              sock_;
            ConnectionInputStream               is_;
            ConnectionOutputStream              os_;

            ConnectionReadableFN                readableFN_;
            ConnectionWritableFN                writableFN_;
            PassConnectionFN                    errorFN_;
            PassConnectionFN                    heartbeatFN_;
            PassConnectionFN                    closeFN_;

            boost::function<void(Connection*)>  shutdownFN_;

            void*                               userPointer_;
        };

        typedef boost::shared_ptr<Connection> ConnectionPtr;
    }
}

#endif //NIO_NET_CONNECTION_HPP_
